package org.jecat.pusher;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

public class Request
{

	public Request()
	{
	}
	
	public void receive(SocketChannel socket) throws ExceptionDisconnect
	{
		String readed = "" ;
		do
		{
			readed = read( socket ) ;
			m_sReceives+= readed ;
			
		} while(readed.length()>0) ;
	}

	public void drop()
	{
		m_aReqParams = null ;
	}
	
	public Boolean hasData()
	{
		return m_sReceives.length()>0 ;
	}
	
	public void buildRequest()
	{
		// flash 请求安全策略
		if( m_sReceives.equals("<policy-file-request/>\0") )
		{
			m_aReqParams = new HashMap<String,String[]>() ;
			m_aReqParams.put("action", new String[]{"policy"}) ;
			m_sReceives = "" ;
		}
		
		// 客户端请求
		else if( m_sReceives.contains("\r\n") )
		{
			int pos = m_sReceives.indexOf("\r\n") ;
			if(pos>0)
			{
				m_aReqParams = parseUrlQueryString(m_sReceives.substring(0,pos)) ;
			}
			
			if( pos < m_sReceives.length()-2 )
			{
				m_sReceives = m_sReceives.substring(pos+2) ;
			}
			else
			{
				m_sReceives = "" ;
			}
		}
	}
	
	public Boolean requestClose()
	{
		return m_requestClose ;
	}

	public void requestClose(Boolean close)
	{
		m_requestClose = close ;
	}
	
	private String read(SocketChannel socket) throws ExceptionDisconnect
	{
		ByteBuffer readBuff = ByteBuffer.allocate(1024) ;
		int reads = 0 ;
		
		try {
			reads = socket.read(readBuff);
		} catch (IOException e) {
			throw new ExceptionDisconnect() ;
		}

		if(reads==-1)		// 连接断开
		{
			throw new ExceptionDisconnect() ;
		}
		else if(reads==0)
		{
			return "" ;
		}

		byte[] bytes = new byte[reads] ;
		readBuff.flip();
		readBuff.get(bytes) ;
		
		return new String(bytes) ;
	}
	
	public Boolean avalid()
	{
		return m_aReqParams != null ;
	}

	public Request(String sReq)
	{
		m_aReqParams = parseUrlQueryString(sReq) ;
	}

	public String[] getParams(String sParam)
	{
		return avalid()? m_aReqParams.get(sParam): null ;
	}
	public String get(String sParam)
	{
		String[] arrParams = getParams(sParam) ;
		if( arrParams==null || arrParams.length<1 )
		{
			return null ;
		}
		
		else
		{
			return arrParams[0] ;
		}
	}
	public String get(String sParam,String sDefault)
	{
		String sValue = get(sParam) ;
		return sValue==null? sDefault: sValue ;
	}
	
	private Map<String, String[]> m_aReqParams;
	
	
	
	public static Map<String, String[]> parseUrlQueryString(String s)
	{
		if (s == null)
		{
			return new HashMap<String, String[]>(0);
		}
		// In map1 we use strings and ArrayLists to collect the parameter
		// values.
		HashMap<String, Object> map1 = new HashMap<String, Object>();
		int p = 0;
		while (p < s.length())
		{
			int p0 = p;
			while (p < s.length() && s.charAt(p) != '=' && s.charAt(p) != '&')
			{
				p++;
			}
			String name = urlDecode(s.substring(p0, p));
			if (p < s.length() && s.charAt(p) == '=')
			{
				p++;
			}
			p0 = p;
			while (p < s.length() && s.charAt(p) != '&')
			{
				p++;
			}
			String value = urlDecode(s.substring(p0, p));
			if (p < s.length() && s.charAt(p) == '&')
			{
				p++;
			}
			Object x = map1.get(name);
			if (x == null)
			{
				// The first value of each name is added directly as a string to
				// the map.
				map1.put(name, value);
			}
			else if (x instanceof String)
			{
				// For multiple values, we use an ArrayList.
				ArrayList<String> a = new ArrayList<String>();
				a.add((String) x);
				a.add(value);
				map1.put(name, a);
			}
			else
			{
				@SuppressWarnings("unchecked")
				ArrayList<String> a = (ArrayList<String>) x;
				a.add(value);
			}
		}
		// Copy map1 to map2. Map2 uses string arrays to store the parameter
		// values.
		HashMap<String, String[]> map2 = new HashMap<String, String[]>(
				map1.size());
		for (Map.Entry<String, Object> e : map1.entrySet()) {
			String name = e.getKey();
			Object x = e.getValue();
			String[] v;
			if (x instanceof String) {
				v = new String[] { (String) x };
			} else {
				@SuppressWarnings("unchecked")
				ArrayList<String> a = (ArrayList<String>) x;
				v = new String[a.size()];
				v = a.toArray(v);
			}
			map2.put(name, v);
		}
		return map2;
	}

	private static String urlDecode(String s)
	{
		try {
			return URLDecoder.decode(s, "UTF-8");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException("Error in urlDecode.", e);
		}
	}

	private String m_sReceives = "" ;
	private Boolean m_requestClose = false ;
}
